package org.springframework.web.filter;

import top.malaoshi.web.utils.CorsUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 处理跨域的过滤器
 */
public class CorsFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse) res;

        // 判断是否跨域
        if(CorsUtils.isCorsRequest(request)){
            configCors(request,response);
        }
        chain.doFilter(req, res);
    }

    /**
     * 配置跨域请求头
     * @param request
     * @param response
     */
    protected void configCors(HttpServletRequest request,HttpServletResponse response){
        setCorsHeader(request,response,
                "*","*","*",true,3600);

    }

    /**
     * 设置跨域的头信息
     * @param request
     * @param response
     * @param allowOrigin
     * @param allowedHeader
     * @param allowMethods
     * @param allowCredentials
     * @param maxAge
     */
    protected void setCorsHeader(HttpServletRequest request, HttpServletResponse response,
                               String allowOrigin,
                               String allowedHeader,
                               String allowMethods,
                               boolean allowCredentials,
                               long maxAge){
        /*
        允许可访问的域列表。携带cookie时，不能是 *，必须填域名，而且末尾不能有符号： /
        跨域必须设置

        如果是 *，表示允许任意前端服务器 跨域（不安全）
        实现原理：跨域时，前端发送请求头中，一定包含 Origin，也就是前端域名，允许该前端域名
         */
        if("*".equals(allowOrigin)) {
            allowOrigin = request.getHeader("Origin");
        }
        response.setHeader("Access-Control-Allow-Origin", allowOrigin);


        //如果是 Preflight 请求
        if(CorsUtils.isPreFlightRequest(request)) {
            /*
            允许携带请求头。携带cookie时，不能是 *

            如果是 *，表示允许任意请求头
            实现原理：跨域时，前端发送非简单请求时，会先发送 Preflight 请求，该请求头中，包含 Access-Control-Request-Headers 头，是正式请求携带的头，允许该请求头

            提示：跨域时，发送简单请求头中，不包含 Access-Control-Request-Headers，此时可以不设置该项
             */
            if("*".equals(allowedHeader)) {
                allowedHeader = request.getHeader("Access-Control-Request-Headers");
            }
            if(allowedHeader !=null && !"".equals(allowedHeader)) {
                response.setHeader("Access-Control-Allow-Headers", allowedHeader);
            }
            /*
            允许跨域的请求方法
            如果是 *，表示允许任意请求方法
            实现原理：跨域时，前端发送非简单请求时，会先发送 Preflight 请求，该请求头中，包含 Access-Control-Request-Method 头，是正式请求的方法，允许该方法

            提示：跨域时，发送简单请求头中，不包含 Access-Control-Request-Method，此时可以不设置该项
             */
            if("*".equals(allowMethods)){
                allowMethods = request.getHeader("Access-Control-Request-Method");
            }
            if(allowMethods !=null && !"".equals(allowMethods)) {
                response.setHeader("Access-Control-Allow-Methods", allowMethods);
            }
            // 设置 Preflight 请求缓存多长时间（以秒为单位）
            response.setHeader("Access-Control-Max-Age", maxAge + "");
            //允许浏览器发送 cookie
            response.setHeader("Access-Control-Allow-Credentials", allowCredentials+"");
        }
    }
    public void init(FilterConfig filterConfig) {}
    public void destroy() {}
}
